#include <bits/stdc++.h>
using namespace std;
#include "GameModel.h"

GameModel::GameModel()
{
    type = BOT;       // 默认人机对战模式
    status = PLAYING; // 默认游戏进行中
    player = true;    // 默认玩家1(白子)先手
}

/**
 * @brief 游戏初始化
 * @param type (PVP/PVE)
 */
void GameModel::start(Type type)
{
    this->type = type;
    status = PLAYING;

    map.clear();
    for (int i = 0; i < kBoardSizeNum; i++)
    {
        vector<int> lineBoard;
        for (int j = 0; j < kBoardSizeNum; j++)
            lineBoard.push_back(0);
        map.push_back(lineBoard);
    }

    // 初始化评分矩阵
    if (type == BOT)
    {
        scores.clear();
        for (int i = 0; i < kBoardSizeNum; i++)
        {
        vector<int> lineScores;
            for (int j = 0; j < kBoardSizeNum; j++)
                lineScores.push_back(0);
            scores.push_back(lineScores);
        }
    }

    player = true;  // 玩家1(执白子)先手
}

/**
 * @brief 刷新游戏状态
 * @param row 行(0-14)
 * @param col 列(0-14)
 */
void GameModel::updateGameMap(int row, int col)
{
    if (player)
        map[row][col] = 1;  // 玩家1(白子)
    else
        map[row][col] = -1; // 玩家2/AI(黑子)

    player = !player; // 切换玩家
}

/**
 * @brief 落子操作
 */
void GameModel::playerMove(int row, int col)
{
    updateGameMap(row, col);
}

/**
 * @brief 贪心决策
 * @param[out] clickRow 落子行
 * @param[out] clickCol 落子列
 */
void GameModel::aiMove(int &row, int &col)
{
    calculateScore();

    /* 寻找最高分位置
     * max记录当前最高分
     * points存储所有等于max的位置 */
    int max = 0;
    vector<pair<int, int>> points;

    for (int r = 1; r < kBoardSizeNum; r++) {
        for (int c = 1; c < kBoardSizeNum; c++) {
            if (map[r][c] == 0) {
                if (scores[r][c] > max) {
                    points.clear();
                    max = scores[r][c];
                    points.push_back({r, c});
                } 
                else if (scores[r][c] == max) {
                    points.push_back({r, c});
                }
            }
        }
    }

    // 随机时间种子选取高分位置,不然没得玩
    // 其实可以每次执行最后push的位置,攻击性会强一点
    srand((unsigned)time(0));
    int index = rand() % points.size();
    row = points[index].first;
    col = points[index].second;

    updateGameMap(row, col);
}

/**
 * @brief 贪心算法
 * 
 * 1. 进攻(形成自己的连子)
 * 2. 防守(阻止对手连子)
 * 3. 八个方向(水平、垂直、对角线)
 */
void GameModel::calculateScore()
{
    // 定义三个计数器变量
    int playerCount = 0; // 统计玩家连续棋子数(用于防守评分)
    int aiCount = 0;    // 统计AI连续棋子数(用于进攻评分)
    int emptyCount = 0;  // 统计空位数量(影响连子发展潜力)

    /* 初始化评分矩阵 
     * 使用vector嵌套实现15x15评分矩阵
     * 每个位置初始分数为0 */
    scores.clear();
    for (int i = 0; i < kBoardSizeNum; i++)
    {
        vector<int> lineScores;
        for (int j = 0; j < kBoardSizeNum; j++)
            lineScores.push_back(0); // 初始化每个位置分数为0
        scores.push_back(lineScores);
    }

    /* 遍历棋盘每个位置进行评分
     * 从(0,0)到(14,14) */
    for (int row = 0; row < kBoardSizeNum; row++)
        for (int col = 0; col < kBoardSizeNum; col++)
        {
            // 只评估空位(值为0的位置)且不在边界上
            if (row > 0 && col > 0 && map[row][col] == 0)
            {
                /* 8方向扫描(实际使用4个有效方向)
                 * y=-1:上一行, y=0:当前行, y=1:下一行
                 * x=-1:左一列, x=0:当前列, x=1:右一列 */
                for (int y = -1; y <= 1; y++)
                    for (int x = -1; x <= 1; x++)
                    {
                        // 不检查标记点本身
                        if (!(y == 0 && x == 0))
                        {
                            // 重置计数器开始新方向的评估
                            playerCount = 0; // 玩家连子数清零
                            aiCount = 0;    // AI连子数清零
                            emptyCount = 0;  // 空位数清零

                            /* 正向扫描(从当前位置向外延伸)
                             * 最多扫描4个位置 */
                            for (int i = 1; i <= 4; i++)
                            {
                                if (row + i * y > 0 && row + i * y < kBoardSizeNum &&
                                    col + i * x > 0 && col + i * x < kBoardSizeNum)
                                {
                                    if (map[row + i * y][col + i * x] == 1)
                                    {
                                        playerCount++;
                                    }
                                    else if (row + i * y > 0 && row + i * y < kBoardSizeNum &&
                                             col + i * x > 0 && col + i * x < kBoardSizeNum &&
                                             map[row + i * y][col + i * x] == 0)
                                    {
                                        emptyCount++;
                                        break;
                                    }
                                    else
                                        break;
                                }

                            // 反方向检测
                            for (int i = 1; i <= 4; i++)
                            {
                                if (row - i * y > 0 && row - i * y < kBoardSizeNum &&
                                    col - i * x > 0 && col - i * x < kBoardSizeNum &&
                                    map[row - i * y][col - i * x] == 1) // 玩家的子
                                {
                                    playerCount++;
                                }
                                else if (row - i * y > 0 && row - i * y < kBoardSizeNum &&
                                         col - i * x > 0 && col - i * x < kBoardSizeNum &&
                                         map[row - i * y][col - i * x] == 0) // 空白位
                                {
                                    emptyCount++;
                                    break;
                                }
                                else            // 出边界
                                    break;
                            }

                            // 根据玩家连子情况增加防守分数
                            // 实际上主要防止两端开发情况的连子
                            if (playerCount == 1)                      // 连2子
                                scores[row][col] += 10;
                            else if (playerCount == 2)                 // 连3子
                            {
                                if (emptyCount == 1)                  // 一端被堵
                                    scores[row][col] += 30;
                                else if (emptyCount == 2)              // 两端开放
                                    scores[row][col] += 1000;
                            }
                            else if (playerCount == 3)                 // 连4子
                            {
                                if (emptyCount == 1)
                                    scores[row][col] += 60;
                                else if (emptyCount == 2)
                                    scores[row][col] += 2000;
                            }
                            else if (playerCount == 4)                 // 连5子
                                scores[row][col] += 10100;

                        } 
                    } 
                } 
            }
    }
}

/**
 * @brief 胜利条件
 * @param row 行
 * @param col 列
 * @return true达成胜利条件，否则false
 */
bool GameModel::isWin(int row, int col)
{
    // 1. 水平
    for (int i = 0; i < 5; i++)
    {
        if (col - i > 0 && 
            col - i + 4 < kBoardSizeNum)
        {
            if (map[row][col - i] != 0 &&
                map[row][col - i] == map[row][col - i + 1] &&
                map[row][col - i] == map[row][col - i + 2] &&
                map[row][col - i] == map[row][col - i + 3] &&
                map[row][col - i] == map[row][col - i + 4])
                return true;
        }
    }

    // 2. 垂直
    for (int i = 0; i < 5; i++)
    {
        if (row - i > 0 &&
            row - i + 4 < kBoardSizeNum)
        {
            if (map[row - i][col] != 0 &&
                map[row - i][col] == map[row - i + 1][col] &&
                map[row - i][col] == map[row - i + 2][col] &&
                map[row - i][col] == map[row - i + 3][col] &&
                map[row - i][col] == map[row - i + 4][col])
                return true;
        }
    }

    // 3. 对角线 
    for (int i = 0; i < 5; i++)
    {
        if (row + i < kBoardSizeNum &&
            row + i - 4 > 0 &&
            col - i > 0 &&
            col - i + 4 < kBoardSizeNum)
        {
            if (map[row + i][col - i] != 0 &&
                map[row + i][col - i] == map[row + i - 1][col - i + 1] &&
                map[row + i][col - i] == map[row + i - 2][col - i + 2] &&
                map[row + i][col - i] == map[row + i - 3][col - i + 3] &&
                map[row + i][col - i] == map[row + i - 4][col - i + 4])
                return true;
        }
    }

    // 4. 反对角线
    for (int i = 0; i < 5; i++)
    {
        if (row - i > 0 &&
            row - i + 4 < kBoardSizeNum &&
            col - i > 0 &&
            col - i + 4 < kBoardSizeNum)
        {
            if (map[row - i][col - i] != 0 &&
                map[row - i][col - i] == map[row - i + 1][col - i + 1] &&
                map[row - i][col - i] == map[row - i + 2][col - i + 2] &&
                map[row - i][col - i] == map[row - i + 3][col - i + 3] &&
                map[row - i][col - i] == map[row - i + 4][col - i + 4])
                return true;
        }
    }

    // 妹有达成胜利套件
    return false;
}

/**
 * @brief 和棋(打不过?)
 * @return 和棋或者已达成胜利条件(结束游戏)，否则false(继续游戏)
 */
bool GameModel::isDeadGame()
{
    for (int i = 1; i < kBoardSizeNum; i++){
        for (int j = 1; j < kBoardSizeNum; j++)
        {
            if (!(map[i][j] == 1 || map[i][j] == -1))
                return false;
        }
    }
    return true;
}
